package com.lifang.framework.context.support;

import com.lifang.framework.aop.framework.support.DefaultAdvisorAutoProxyCreator;
import com.lifang.framework.beans.BeansException;
import com.lifang.framework.beans.factory.BeanFactory;
import com.lifang.framework.beans.factory.ConfigurableListableBeanFactory;
import com.lifang.framework.beans.factory.annotation.CommonAnnotationBeanPostProcessor;
import com.lifang.framework.beans.factory.config.ApplicationEventMulticaster;
import com.lifang.framework.beans.factory.config.BeanFactoryPostProcessor;
import com.lifang.framework.beans.factory.config.BeanPostProcessor;
import com.lifang.framework.beans.factory.event.ContextClosedEvent;
import com.lifang.framework.beans.factory.event.ContextRefreshedEvent;
import com.lifang.framework.beans.factory.event.SimpleApplicationEventMulticaster;
import com.lifang.framework.beans.factory.support.DefaultListableBeanFactory;
import com.lifang.framework.context.ApplicationContext;
import com.lifang.framework.context.ApplicationEventPublisher;
import com.lifang.framework.context.ApplicationListener;
import com.lifang.framework.context.ConfigurableApplicationContext;
import com.lifang.framework.context.config.ApplicationEvent;
import com.lifang.framework.core.convert.support.GenericConversionService;
import com.lifang.framework.core.io.DefaultResourceLoader;
import lombok.extern.slf4j.Slf4j;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Map;

@Slf4j
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

    private ApplicationEventMulticaster applicationEventMulticaster;

    protected abstract void refreshBeanFactory() throws BeansException;

    protected abstract ConfigurableListableBeanFactory getBeanFactory();

    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBeansOfType(requiredType);
    }

    @Override
    public <T> T getBean(Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(requiredType);
    }

    @Override
    public String[] getBeanDefinitionNames() {
        return getBeanFactory().getBeanDefinitionNames();
    }

    @Override
    public Object getBean(String name) throws BeansException {
        return getBeanFactory().getBean(name);
    }

    @Override
    public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException {
        return getBeanFactory().getBeansWithAnnotation(annotationType);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return getBeanFactory().getBean(name, args);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(name, requiredType);
    }

    @Override
    public Class<?> getType(String beanName) {
        return getBeanFactory().getBeanDefinition(beanName).getBeanClass();
    }

    @Override
    public String[] getBeanNamesForType(Class<?> requiredType) {
        return getBeanFactory().getBeanNamesForType(requiredType);
    }

    @Override
    public void publishEvent(ApplicationEvent event) {
        applicationEventMulticaster.multicastEvent(event);
    }

    @Override
    public void registerShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(this::close));
    }

    @Override
    public void close() {
        // 发布容器关闭广播事件
        publishEvent(new ContextClosedEvent(this));

        // 执行bean的销毁方法
        getBeanFactory().destroySingletons();
    }

    @Override
    public void refresh() {
        DefaultListableBeanFactory beanFactory = prepareBeanFactory();

        // 注册并执行BeanFactoryProcessor增强器
        invokeBeanFactoryPostProcessors(beanFactory);

        // 注册BeanPostProcessor
        registerBeanPostProcessors(beanFactory);

        // 初始化事件发布者
        initApplicationEventMulticaster();

        // 注册事件监听器
        registersListeners();

        // 提前实例化单例Bean对象
        finishBeanFactoryInitialization(beanFactory);

        // 注册实例化销毁方法
        registerShutdownHook();

        // 容器刷新完成
        finishRefresh();
    }

    protected DefaultListableBeanFactory prepareBeanFactory() {
        // 创建 BeanFactory，并加载 BeanDefinition
        refreshBeanFactory();

        // 获取 BeanFactory
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) getBeanFactory();
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);

        // 注册值解析器
        beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
        // 注册aop代理器
        beanFactory.addBeanPostProcessor(new DefaultAdvisorAutoProxyCreator());

        // 注册类型转换器
        beanFactory.setConversionService(new GenericConversionService());
        return beanFactory;
    }

    /**
     * 提起实例化单例对象等
     */
    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        beanFactory.preInstantiateSingletons();
    }

    private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        String[] beanNames = getBeanNamesForType(BeanFactoryPostProcessor.class);
        for (String beanName : beanNames) {
            BeanFactoryPostProcessor factoryBean = (BeanFactoryPostProcessor) beanFactory.getBean(beanName);
            factoryBean.postProcessBeanFactory(beanFactory);
        }
    }

    private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        String[] beanNames = getBeanNamesForType(BeanPostProcessor.class);
        Arrays.stream(beanNames).forEach(item -> beanFactory.addBeanPostProcessor((BeanPostProcessor) beanFactory.getBean(item)));
    }

    /**
     * 初始化事件发布者
     */
    private void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, applicationEventMulticaster);
    }

    /**
     * 注册事件监听器
     */
    @SuppressWarnings("unchecked")
    private void registersListeners() {
        String[] beanNames = getBeanNamesForType(ApplicationListener.class);
        for (String beanName : beanNames) {
            applicationEventMulticaster.addApplicationListener((ApplicationListener<ApplicationEvent>) getBean(beanName));
        }
    }

    @Override
    public boolean containsBean(String beanName) {
        return getBeanFactory().containsBean(beanName);
    }

    /**
     * 完成事件注册
     */
    private void finishRefresh() {
        publishEvent(new ContextRefreshedEvent(this));
    }

}
